package cn.push.embed.core.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

import cn.push.embed.core.utils.Logger;
import cn.push.embed.protocol.Constant;
import cn.push.embed.protocol.Utils;


public class NioSocketConnection implements NioSocket {
    private static final boolean DEBUG = true;
    private static final String TAG = NioSocketConnection.class.getName();

    protected Selector selector;
    protected SocketChannel socketChannel;
    private String nsHost;
    private int nsPort;
    private byte[] header;
    private boolean mActive;
    private ConnectionHandler nsHandler;

    @Override
    public void connect(String url, ConnectionHandler nsHandler) {
        this.nsHandler = nsHandler;
        String[] parameters = url.split(":");
        nsHost = parameters[0];
        nsPort = Integer.parseInt(parameters[1]);
        try {
            socketChannel = SocketChannel.open(new InetSocketAddress(nsHost, nsPort));
            socketChannel.configureBlocking(false);            //设置为非阻塞模式
            selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_READ);
            mActive = true;

            new NioSocketReceiveThread(this);
            nsHandler.onOpen();
        } catch (IOException e) {
            nsHandler.onClose(ConnectionHandler.CLOSE_CANNOT_CONNECT, "Connection could not be established in the first place");
            mActive = false;
            this.disConnect();
            e.printStackTrace();
        }

    }


    @Override
    public void disConnect() {
        mActive = false;
        try {
            if (socketChannel != null) {
                socketChannel.close();
                socketChannel = null;
            }
            if (selector != null) {
                selector.close();
                selector = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public boolean isConnected() {
        if (this.socketChannel != null) {
            return this.socketChannel.isConnected();
        }
        return false;
    }

    @Override
    public void sendBinaryMessage(byte[] payload) {
        ByteBuffer writeBuffer = ByteBuffer.wrap(payload);
        //writeBuffer.put(payload);
        try {
            socketChannel.write(writeBuffer);
        } catch (IOException e) {
            this.mActive = false;
            this.disConnect();
            this.nsHandler.onClose(ConnectionHandler.CLOSE_CONNECTION_LOST, "A previously established connection was lost unexpected");
            e.printStackTrace();
        }

    }

    @Override
    public void sendRawTextMessage(byte[] payload) {
        sendBinaryMessage(payload);
    }

    @Override
    public void sendTextMessage(String payload) {
        try {
            ByteBuffer writeBuffer = ByteBuffer.wrap(payload.getBytes("UTF-8"));
            socketChannel.write(writeBuffer);
        } catch (IOException e) {
            this.mActive = false;
            this.disConnect();
            this.nsHandler.onClose(ConnectionHandler.CLOSE_CONNECTION_LOST, "A previously established connection was lost unexpected");
            e.printStackTrace();
        }

    }

    @Override
    public void sendPingFrame() {
        byte[] data = {0x01};
        byte[] result = null;
        result = Utils.getSendPagectFromInt(data, Constant.DataType.LPUSH_HEADER_TYPE_HREATBEAT);


        sendBinaryMessage(result);
        Logger.d("发送心跳:"
                + Arrays.toString(result));

    }

    public Selector getSelector() {
        return selector;
    }

    public void setSelector(Selector selector) {
        this.selector = selector;
    }

    public SocketChannel getSocketChannel() {
        return socketChannel;
    }

    public void setSocketChannel(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
    }

    public boolean ismActive() {
        return mActive;
    }


    public void setmActive(boolean mActive) {
        this.mActive = mActive;
    }


    public ConnectionHandler getNsHandler() {
        return nsHandler;
    }


    public void setNsHandler(ConnectionHandler nsHandler) {
        this.nsHandler = nsHandler;
    }


}
